package com.lyl.security.module.login.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.lyl.security.common.constant.Constants;
import com.lyl.security.common.utils.RedisUtil;
import com.lyl.security.module.login.service.TokenService;
import com.lyl.security.module.security.model.details.LoginUser;
import com.lyl.security.module.security.model.properties.SecurityProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author Mr.Luo
 * @date 2022-09-13 16:19
 * @desc
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TokenServiceImpl implements TokenService {
    private final SecurityProperties securityProperties;

    @Override
    public String createToken(LoginUser loginUser) {
        String uuid = IdUtil.fastUUID();
        loginUser.setToken(uuid);
        refreshToken(loginUser);
        return createToken(uuid);
    }

    private void refreshToken(LoginUser loginUser) {
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setExpiredTime(loginUser.getLoginTime() + securityProperties.getToken().getExpiredTime() * Constants.MINUTE);
        RedisUtil.set(Constants.LOGIN_TOKEN_KEY + loginUser.getToken(), loginUser, securityProperties.getToken().getExpiredTime(), TimeUnit.MINUTES);
    }

    @Override
    public LoginUser getLoginUser(HttpServletRequest request) {
        String token = getToken(request);
        if (CharSequenceUtil.isNotBlank(token)) {
            try {
                Claims claims = parseToken(token);
                // 解析对应的权限以及用户信息
                String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
                String userKey = Constants.LOGIN_TOKEN_KEY + uuid;
                return JSONUtil.toBean(JSONUtil.toJsonStr(RedisUtil.get(userKey)), LoginUser.class);
            } catch (Exception e) {
            }
        }
        return null;
    }

    @Override
    public void verifyToken(LoginUser loginUser) {
        long expiredTime = loginUser.getExpiredTime();
        long currentTime = System.currentTimeMillis();
        if ((expiredTime - currentTime) <= Constants.TEN_MINUTE) {
            refreshToken(loginUser);
        }
    }

    private String getToken(HttpServletRequest request) {
        String token = request.getHeader(securityProperties.getToken().getHeader());
        if (CharSequenceUtil.isNotBlank(token) && token.startsWith(Constants.TOKEN_PREFIX)) {
            token = token.replace(Constants.TOKEN_PREFIX, "");
        }
        return token;
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    private Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(securityProperties.getToken().getSecret())
                .parseClaimsJws(token)
                .getBody();
    }

    public String createToken(String token) {
        Map<String, Object> claims = MapUtil.builder(Constants.LOGIN_USER_KEY, (Object) token).build();
        return Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, securityProperties.getToken().getSecret()).compact();
    }
}
